﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Mnk.Merger.Code.Repository;
using Mnk.Merger.Code.Settings;

namespace Mnk.Merger.Code.Commands
{
    class BulkOperations : IBulkOperations
    {
        private readonly IMerger merger;
        private readonly IMergePathsBuilder mergePathsBuilder;
        private readonly MergeConfig config;
        private readonly IRepositoryFacade facade;

        public BulkOperations(IMerger merger, IMergePathsBuilder mergePathsBuilder, MergeConfig config, IRepositoryFacade facade)
        {
            this.merger = merger;
            this.mergePathsBuilder = mergePathsBuilder;
            this.config = config;
            this.facade = facade;
        }

        public void BulkMerge(bool validate)
        {
            DoBulk(pn => DoAutoMerge(pn, validate));
        }

        public void BulkSwitch(string targetSourceUrl)
        {
            if (!targetSourceUrl.EndsWith("/")) targetSourceUrl += "/";
            DoBulk(pn => DoSwitch(targetSourceUrl, pn));
        }

        private void DoBulk(Action<string> action)
        {
            var projects =
                (config.BulkProjectsNames ?? string.Empty).Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries)
                    .Select(x => x.Trim())
                    .ToArray();
            if (!projects.Any())
            {
                projects =
                    new DirectoryInfo(config.SourcesFolder).GetDirectories()
                        .Where(x => !x.Attributes.HasFlag(FileAttributes.Hidden))
                        .Select(x => x.Name)
                        .ToArray();
            }
            var count = projects.Length;
            var i = 0;
            var failed = new List<string>();
            foreach (var projectName in projects)
            {
                try
                {
                    Console.WriteLine("Bulk operation: {0}/{1}", ++i, count);
                    action(projectName);
                }
                catch (Exception ex)
                {
                    failed.Add(projectName);
                    Console.WriteLine(ex);
                }
            }
            if (failed.Any())
            {
                Console.WriteLine("Next projects failed:");
                Console.WriteLine(string.Join(Environment.NewLine, projects));
            }
        }

        private void DoAutoMerge(string projectName, bool validate)
        {
            string workingDirectory, mergeUrl, revisions;
            if (mergePathsBuilder.BuildParams(projectName, out workingDirectory, out mergeUrl, out revisions))
            {
                merger.DoAutoMerge(workingDirectory, mergeUrl, revisions, validate);
            } 
        }

        private void DoSwitch(string targetSourceUrl, string projectName)
        {
            Console.WriteLine("Starting switch '{0}'", projectName);
            var targetFolder = Path.Combine(config.SourcesFolder, projectName);
            var targetUrl = targetSourceUrl + projectName;
            var sourceUrl = facade.GetInfo(targetFolder).Url;
            facade.CleanUp(targetFolder);
            facade.Revert(targetFolder);
            if (string.Equals(targetUrl, sourceUrl, StringComparison.OrdinalIgnoreCase))
            {
                Console.WriteLine("Can't switch. It is already switched.");
                return;
            }
            Console.WriteLine("Switch to: '{0}', from: '{1}'",  targetUrl, sourceUrl);
            facade.Switch(targetFolder, targetUrl);
        }

    }
}
